import java.text.SimpleDateFormat;
import java.util.Calendar;

import controlP5.*;
import de.fhpotsdam.unfolding.geo.Location;
import processing.core.*;

public class outofthesky extends PApplet {
	//Serial number... ignore.
	private static final long serialVersionUID = 1L;
	
	
	DataParser dataAP;	//Airports
	DataParser dataMB;	//Militaary Bases
	DataParser dataAS;  //Alien Sightings
	DataParser dataPop;	//Population Density
	DataParser dataWS;	//Weather Stations
	Menu topMenu;
	
	private graphData listMB, listAir, listWS, listYear, listMonth, listHour, listPop;
	
	SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy");	//For comparing dates.
	
	boolean newRange = true;
	boolean invalidRange = false;
	
	//Graph test
	Graph theGraph = new Graph(0,100, 1024, 580);
	int currentGraph = 0;	//Represents type of graph currently selected.
	
	private int count = 0;
	
	public void setup() {
		GLOBAL g = new GLOBAL(this);
		g.initTypes();
		
		//Parse necessary data
		dataAP = new DataParser("airports.txt");
		dataMB = new DataParser("militaryBase.txt");
		dataAS = new DataParser("sightings.txt");
		dataPop = new DataParser("population.txt");
		dataWS = new DataParser("weatherstations.txt");
		
		listMB = new graphData("militaryBase_Distance_Histogram.txt"); 
		listAir = new graphData("airport_Distance_Histogram.txt");
		listWS = new graphData("weatherStation_Distance_Histogram.txt");
		listYear = new graphData("sighting_Year_Histogram.txt");
		listMonth = new graphData("sighting_Month_Histogram.txt");
		listHour = new graphData("sighting_Hour_Histogram.txt");

		size(1024, 720);
		
		initColors();			//Initialize colors
		
		topMenu = new Menu();	//Create Menu
		
		GLOBAL.displayMap = true; 				//=> Program will initially display map.
		GLOBAL.THE_MAP = new UnfoldingMap();	//Initialize map to be displayed.
		
		//Deafult Values for start and end date
		GLOBAL.DATE_START.set(2010, 1, 1);
		GLOBAL.DATE_END.set(2010, 11, 31);
		
		hint(ENABLE_OPENGL_4X_SMOOTH);
		smooth();
	}
	
	public void draw() {
		//Map-mode => display map (as opposed to graph-mode)
		//Display map when in map-mode (as opposed to graph-mode)
		if(GLOBAL.displayMap) {
			GLOBAL.THE_MAP.draw();
			
			//Draw grey borders (along top/bottom of map)
			noStroke();
			fill(200);
			rect(0,0,1024,100);
			rect(0,580,1024,720);
			
			//Display Population Desnity (if selected)
			if(topMenu.getPoplulationStatus())
				drawPopulation();
			
			//Display Airports (if selected)
			if(topMenu.getAirportStatus())
				drawAirports();
				
			//Display Military Bases (if selected)
			if(topMenu.getMilitaryStatus())
				drawMilitaryBases();
			
			//Display Weather Staations (if selected)
			if(topMenu.getWeatherStatus())
				drawWeatherStations();
			
			if(!invalidRange) {
				topMenu.updateSelectedTypes();
				drawSightings();
			}
			
		}//End draw map-mode
		
		//Graph-Mode
		else {
			drawGraph();
			
			//Draw grey borders (along top/bottom of map)
			noStroke();
			fill(200);
			rect(0,0,1024,100);
			rect(0,580,1024,720);
		}
		
		//Draw grey borders (along top/bottom of map)
		noStroke();
		fill(200);
		rect(0,0,1024,100);
		
		if(GLOBAL.isInfoShowingWS)
			rect(500, 580, 1024, 720);
		
		//Only draw bottom border when there is no info there
		if(!GLOBAL.isInfoShowingS && !GLOBAL.isInfoShowingMB && !GLOBAL.isInfoShowingAir & !GLOBAL.isInfoShowingWS)
			rect(0,580,1024,720);
		
		if(invalidRange) {
			fill(0);
		 	text("Invalid Date Range", 440, 92);
		}
		
		//Draw Menu
		GLOBAL.controlP5.draw();
		
		//Draw Menu Labels & Dividers
		GLOBAL.processing.textAlign(LEFT);
		fill(0);
		text("Start Date", 343, 25);
		text("End Date", 514, 25);
		text("UFO Types", 700, 25);
		text("Additional Data", 895, 25);
		stroke(110);
		line(675, 10, 675, 90);
		line(870, 10, 870, 90);
		
		if(!GLOBAL.displayMap)
			text("Graph Types", 40, 610); 
		else {
			text("Currently Displaying " + count + " Sightings", 750, 610);
			
			int mo1 = GLOBAL.DATE_START.get(Calendar.MONTH);
			int yr1 = GLOBAL.DATE_START.get(Calendar.YEAR);
			int mo2 = GLOBAL.DATE_END.get(Calendar.MONTH);
			int yr2 = GLOBAL.DATE_END.get(Calendar.YEAR);
			
			if(mo1 == 0) { mo1 = 12; yr1--;}
			if(mo2 == 0) { mo2 = 12; yr2--;}
			
			text("From: " + mo1 + "/" + GLOBAL.DATE_START.get(Calendar.DATE) + "/" + yr1, 750, 625);
			text("Through: " + mo2 + "/" + GLOBAL.DATE_END.get(Calendar.DATE) + "/" + yr2, 750, 640);
		}
		
		//drawKey();
	}
	
	public void drawKey(){
		new MilitaryBase(20, 600, 12, 11, "", "").draw();
		//new Airport(20, 612, "", "").draw();
	}
	
	public void drawWeatherStations() {
		GLOBAL.isInfoShowingWS = false;
		fill(GLOBAL.colorAirport);
		
		Location loc;	//Location of military base
		float[] pos;	//Position on screen of military base : pos[0] = x & pos[1] = y
		
		//Parse all Weather Stations
		for(int x=0; x<dataWS.rowCount; ++x) {
			loc = new Location(dataWS.getLatitude(x), dataWS.getLongitude(x));
			pos = GLOBAL.THE_MAP.map.getScreenPositionFromLocation(loc);
			
			if(pos[1] >= 100 && pos[1] <= 580) {
			
			new WeatherStation(pos[0], pos[1],  GLOBAL.THE_MAP.map.getZoomLevel(), GLOBAL.THE_MAP.map.getZoomLevel()-1, 
								dataWS.getName(x), dataWS.getAltNames1(x))
								.draw();
			}
		}
	}
	
	public void drawAirports() {
		GLOBAL.isInfoShowingAir = false;
		fill(GLOBAL.colorAirport);
		
		Location loc;	//Location of military base
		float[] pos;	//Position on screen of military base : pos[0] = x & pos[1] = y
		
		//Parse all Airports
		for(int x=0; x<dataAP.rowCount; ++x) {
			loc = new Location(dataAP.getLatitude(x), dataAP.getLongitude(x));
			pos = GLOBAL.THE_MAP.map.getScreenPositionFromLocation(loc);
			
			if(pos[1] >= 100 && pos[1] <= 580) {
			
			new Airport(pos[0], pos[1], dataAP.getName(x), dataAP.getAltNames3(x))
						.draw();
			
			}
		}
	}
	
	public void drawPopulation() {
		Location loc;	//Location of city
		float pos[];	//Position on screen of city
		float pop;		//Popluation total in city
		          
		//Parse all locations with population info
		for(int x=0; x<dataPop.rowCount; ++x) {
			loc = new Location(dataPop.getLatitude(x), dataPop.getLongitude(x));
			pos = GLOBAL.THE_MAP.map.getScreenPositionFromLocation(loc);
			
			pop = Float.parseFloat(dataPop.getName(x));
			
			if(pos[1] >= 100 && pos[1] <= 580) {
				new Population(pos[0], pos[1], pop, "").draw();
			}
		}
	}
	
	//Called when user wishes to display Military Bases on the map
	public void drawMilitaryBases() {
		GLOBAL.isInfoShowingMB = false;
		fill(GLOBAL.colorMilitary);
		
		Location loc;	//Location of military base
		float[] pos;	//Position on screen of military base : pos[0] = x & pos[1] = y
		
		//Parse all Military Bases
		for(int x=0; x<dataMB.rowCount; ++x) {
			loc = new Location(dataMB.getLatitude(x), dataMB.getLongitude(x));
			pos = GLOBAL.THE_MAP.map.getScreenPositionFromLocation(loc);
			
			if(pos[1] >= 100 && pos[1] <= 580) {
			new MilitaryBase(pos[0], pos[1], GLOBAL.THE_MAP.map.getZoomLevel(), GLOBAL.THE_MAP.map.getZoomLevel()-1,
							dataMB.getName(x), dataMB.getAltNames2(x))
							.draw();
			}
		}
	}

	//Called when user wishes to update map display
	//(Presses "Update" & input is valid)
	public void drawSightings() {
		GLOBAL.isInfoShowingS = false;
		Calendar temp = Calendar.getInstance();
		count = 0;
		
		for(int n=0; n<dataAS.rowCount; n+=1) {
			temp.set(Integer.parseInt(dataAS.getAltNames1(n).substring(6)) + 2000, 
					Integer.parseInt(dataAS.getAltNames1(n).substring(3,5)),
					Integer.parseInt(dataAS.getAltNames1(n).substring(0,2)));
			
			int type = GLOBAL.getSightingType(dataAS.names[n]);
			
			if(temp.after(GLOBAL.DATE_END)) {
				break;
			}
			
			if(!temp.before(GLOBAL.DATE_START) && GLOBAL.selectedTypes[type] == 1) {
				String args[] = new String[6]; 
				args[0] = dataAS.getAltNames1(n) + "  " + dataAS.getAltNames2(n);
				args[1] = dataAS.getAltNames3(n) + ", " + dataAS.getAltNames4(n);
				args[2] = "Sighting Type: " + dataAS.names[n];
				args[3] = "Description: " + dataAS.getAltNames5(n);
				args[4] = "Nearest Facility: " + dataAS.getAltNames6(n) + " (mi)";
				args[5] = "     " + dataAS.getAltNames8(n).toLowerCase() + "   (" + dataAS.getAltNames7(n) + ")";
				
				Location loc = new Location(dataAS.getLatitude(n), dataAS.getLongitude(n));
				float[] pos = GLOBAL.THE_MAP.map.getScreenPositionFromLocation(loc);
				
				if(pos[1] >= 100 && pos[1] <= 580) {
				new Sighting(pos[0], pos[1], GLOBAL.THE_MAP.map.getZoomLevel()+4, GLOBAL.THE_MAP.map.getZoomLevel()+3,
						type, args)
						.draw();
				++count;
				}
			}
			
			
		}
	}
	
	//Draw graph corresponding to its integer value
	private void drawGraph() {
		switch(currentGraph) {
		case 0:	//Sightings vs. Distance from Military Base
			theGraph.setTitle("Sightings vs. Distance from Military Base (2001-2010)");
			theGraph.setXLabel("Sighting Distance from Military Base (mi)");
			theGraph.setYLabel("Number of Sightings");
			theGraph.drawData(listMB, 50, 100);
			theGraph.drawXLabelsDistance(listMB, 25, 50);
			break;
		case 1: //Sightings vs. Distance from Airport
			theGraph.setTitle("Sightings vs. Distance from Airport (2001-2010)");
			theGraph.setXLabel("Sighting Distance from Airport (mi)");
			theGraph.setYLabel("Number of Sightings");
			theGraph.setYStart(-1);
			theGraph.drawData(listAir, 100, 500);
			theGraph.drawXLabelsDistance(listAir, 10, 20);
			break;
		
		case 2: //Sightings vs. Distance from Airport
			theGraph.setTitle("Sightings vs. Distance from Weather Station (2001-2010)");
			theGraph.setXLabel("Sighting Distance from Weather Station (mi)");
			theGraph.setYLabel("Number of Sightings");
			theGraph.setYStart(-1);
			theGraph.drawData(listWS, 100, 200);
			theGraph.drawXLabelsDistance(listWS, 5, 10);
			break;
			
		case 3: //Sightings by Time of Day
			theGraph.setTitle("Sightings vs. Time of Day (2001-2010)");
			theGraph.setXLabel("Hour (Military Time)");
			theGraph.setYLabel("Number of Sightings");
			theGraph.setYStart(500);
			theGraph.drawData(listHour, 250, 500);
			theGraph.drawXLabelsSequential(listHour);
			break;
			
		case 4:	//Sightings by Time of Year
			theGraph.setTitle("Sightings vs. Time of Year (2001-2010)");
			theGraph.setXLabel("Month");
			theGraph.setYLabel("Number of Sightings");
			theGraph.setYStart(-1);
			theGraph.drawData(listMonth, 50, 200);
			theGraph.drawXLabelsSequential(listMonth);
			break;
		
		case 5: //Sightings by Year
			theGraph.setTitle("Sightings Year by Year (2001-2010)");
			theGraph.setXLabel("Year");
			theGraph.setYLabel("Number of Sightings");
			theGraph.setYStart(2600);
			theGraph.drawData(listYear, 50, 100);
			theGraph.drawXLabelsSequential(listYear);
			break;
		}
	}
	
	//Initialize colors
	public void initColors(){
		GLOBAL.colorUnknown = GLOBAL.processing.color(255);
		GLOBAL.colorOther = GLOBAL.processing.color(50, 204, 204);
		GLOBAL.colorLight = GLOBAL.processing.color(255, 255, 140);
		GLOBAL.colorTriangle = GLOBAL.processing.color(70, 113, 213);
		GLOBAL.colorRect = GLOBAL.processing.color(255, 105, 180);
		GLOBAL.colorCircle = GLOBAL.processing.color(255, 150, 65);
		
		GLOBAL.colorMilitary = GLOBAL.processing.color(17, 119, 51);
		GLOBAL.colorRollover = GLOBAL.processing.color(200);
		GLOBAL.colorPopulation = GLOBAL.processing.color(143, 188, 143);
		GLOBAL.colorAirport = GLOBAL.processing.color(230, 210, 255);
		GLOBAL.colorWeather = GLOBAL.processing.color(173, 216, 230);
		
		GLOBAL.colorButtonActive = GLOBAL.processing.color(8, 162, 207);
		GLOBAL.colorButtonInactive = GLOBAL.processing.color(0, 54, 82);
		
		GLOBAL.colorGraphBackground = GLOBAL.processing.color(180, 190, 200);
		GLOBAL.colorGraphAxis = GLOBAL.processing.color(75);
		GLOBAL.colorGraphLine = GLOBAL.processing.color(140, 40, 220);
	}
	
	public static void main(String args[]) {
		PApplet.main(new String[]{"--present --location=0,0", "outofthesky"});
	}
	
	public void controlEvent(ControlEvent theEvent) {
		 if (theEvent.isGroup()) {
			 //Update days the user can select from (eg. in Februrary, is 28 or 29 depending on the year selected)
			 if(theEvent.group().name().equals("month1") ||
					 theEvent.group().name().equals("year1") ) { //User changed starting month or year
				 topMenu.updateDays(1);
			 }
			 
			 if(theEvent.group().name().equals("month2") ||
					 theEvent.group().name().equals("year2") ) { //User changed ending month or year
				 topMenu.updateDays(2);
			 }
			 
			 //User is changing graph selection
			 else if(theEvent.group().name().equals("graph_buttons")) {
				 currentGraph = (int) theEvent.group().value();
			 }		 
		 } 
		 else if(theEvent.isController()) {
			 //Update Map/Graph
			 if(theEvent.controller().name().equals("update")) {
				 //Update global values representing date range
				 if(topMenu.isValidRange()) {
					 invalidRange = false;
					 topMenu.updateGlobals();
				 }
				 	

				 else
					invalidRange = true;
			 }
			 
			 //Enter Graph Mode
			 else if(theEvent.controller().name().equals("bgraph")) {
				 GLOBAL.displayMap = false;
				 topMenu.setActiveTab(theEvent.controller().name());
			 }
				 
			 //Enter Map Mode
			 else if(theEvent.controller().name().equals("bmap")) {
		    	GLOBAL.displayMap = true;
		    	topMenu.setActiveTab(theEvent.controller().name());
			 }
		 }

	}
}
